home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / ingres04.lzh / source / qrymod / protect.c < prev    next >
Encoding:
C/C++ Source or Header  |  1985-04-15  |  23.2 KB  |  944 lines

  1. # include    <ingres.h>
  2. # include    <aux.h>
  3. # include    <catalog.h>
  4. # include    <symbol.h>
  5. # include    <tree.h>
  6. # include    "qrymod.h"
  7. # include    <sccs.h>
  8. # include    <errors.h>
  9.  
  10. SCCSID(@(#)protect.c    8.4    4/15/85)
  11.  
  12. /*
  13. **  PROTECT -- protection algorithm
  14. **
  15. **    This module performs the INGRES protection algorithm, as
  16. **    presented in Stonebraker & Rubinstein, "The INGRES Protection
  17. **    System", with a few modifications.
  18. **
  19. **    The basic algorithm is as follows:
  20. **
  21. **    The algorithm is applied once to each variable used in the
  22. **    query.  Each variable has an initial check performed to
  23. **    determine applicability -- if the current user owns the
  24. **    relation, or if the relation is specially marked as being
  25. **    "all access to everyone", then the algorithm is skipped,
  26. **    thereby having effectively no restriction.
  27. **
  28. **    The set of all such variables is computed in 'protect',
  29. **    and then 'dopro' is called to process each of those.  This
  30. **    is so the protection algorithm does not get applied recursively
  31. **    to constraints which define more than one variable.  Notice
  32. **    that this could in itself be a protection violation, if it
  33. **    were acceptable to reference a relation you do not own in a
  34. **    PERMIT statement.
  35. **
  36. **    The effective query mode for this variable is then computed.
  37. **    This is the same as the query mode of the whole query if
  38. **    the variable in question is the result variable, otherwise
  39. **    it is "retrieve" mode.
  40. **
  41. **    The next step is to scan the query tree and create sets of
  42. **    domains referenced.  Four sets are created:
  43. **        uset -- the set of domains updated (actually,
  44. **            referenced in the target list -- on a
  45. **            retrieve, this will be the set of domains
  46. **            retrieved to the user).
  47. **        rset -- the set of domains retrieved in some
  48. **            context other than the left hand side of
  49. **            an equal sign.
  50. **        aset -- the set of domains aggregated.  This only
  51. **            includes domains aggregated with a simple
  52. **            aggregate (not an aggregate function) with
  53. **            no qualification, since it may be possible
  54. **            to come up with too much information other-
  55. **            wise.
  56. **        qset -- the set of domains retrieved for use in
  57. **            a qualification, but never stored.  This
  58. **            includes domains in a qualification of an
  59. **            aggregate or aggregate function.
  60. **    For more details of domains in each of these sets, look at
  61. **    the routine 'makedset'.
  62. **
  63. **    If we had a retrieve operation in the first place, we will
  64. **    then merge 'uset' into 'rset' and clear 'uset', so that
  65. **    now 'uset' only contains domains which are actually updated,
  66. **    and 'rset' contains all domains which are retrieved.
  67. **
  68. **    Now that we know what is referenced, we can scan the protection
  69. **    catalog.  We scan the entire catalog once for each variable
  70. **    mentioned in the query (except as already taken care of as
  71. **    described above).
  72. **
  73. **    We must create a set of all operations on this variable which
  74. **    are not yet resolved, that is, for which no PERMIT statements
  75. **    which qualify have been issued.  We store this set in the
  76. **    variable "noperm".  As PERMIT statements are found, bits will
  77. **    be cleared.  If the variable is not zero by the end of the
  78. **    scan of the protection catalog, then we reject the query,
  79. **    saying that we don't have permission -- giving us default
  80. **    to deny.
  81. **
  82. **    For each tuple in the protection catalog for this relation,
  83. **    we call "proappl" to see if it applies to this query.  This
  84. **    routine checks the user, terminal, time of day, and so forth
  85. **    (in fact, everything which is query-independent) and tells
  86. **    whether this tuple might apply.
  87. **
  88. **    If the tuple passes this initial check, we then do the query-
  89. **    dependent checking.  This amounts to calling "prochk" once
  90. **    for each operation (and domain set) in the query.  What we
  91. **    get back is a set of operations which this tuple applies to.
  92. **    If zero, the tuple doesn't apply at all; otherwise, it
  93. **    applies to at least one operation.  If it applies to some-
  94. **    thing, we call it "interesting".
  95. **
  96. **    For "interesting" tuples, we now get the corresponding
  97. **    qualification (if one exists), and disjoin it to a set of
  98. **    protection constraints held in "pqual".  Also, we mark
  99. **    any operations we found as having been done, by clearing
  100. **    bits in "noperm".
  101. **
  102. **    When we have completed scanning the protection catalog,
  103. **    we check "noperm".  If it is non-zero, then we have some
  104. **    operation for which a PERMIT statement has not been issued,
  105. **    and we issue an error message.  If this variable is ok,
  106. **    then we go on and try the next variable.
  107. **
  108. **    When all variables have been accounted for, we check to
  109. **    see if we have any qualifications collected from the
  110. **    protection algorithm.  If so, we conjoin them to the
  111. **    query tree.
  112. **
  113. **    Finally, we return the root of the modified tree.  This
  114. **    tree is guaranteed to have no authorization violations,
  115. **    and may be run as a regular query.
  116. **
  117. **    Parameters:
  118. **        root -- the root of the tree.
  119. **
  120. **    Returns:
  121. **        The root of the modified and authorized tree.
  122. **
  123. **    Side Effects:
  124. **        A possible non-local return on access violation.
  125. **
  126. **    Trace Flags:
  127. **        50 - 59
  128. */
  129.  
  130. int Proopmap[MAXPROQM + 1] =
  131. {
  132.     PRO_RETR,        /* 0 -- mdRETTERM */
  133.     PRO_RETR,        /* 1 -- mdRETR */
  134.     PRO_APP,        /* 2 -- mdAPP */
  135.     PRO_REPL,        /* 3 -- mdREPL */
  136.     PRO_DEL,        /* 4 -- mdDEL */
  137. };
  138.  
  139. extern QTREE    Prodes;
  140. extern char    Terminal[];
  141. extern QTREE    *gettree();
  142.  
  143.  
  144. QTREE *
  145. protect(root)
  146. QTREE    *root;
  147. {
  148.     register QTREE    *r;
  149.     register int    i;
  150.     register int    vn;
  151.     register DESC    *d;
  152.     int        qmode;
  153.     int        varset;
  154.  
  155.     r = root;
  156.  
  157. #    ifdef xQTR1
  158.     tTfp(50, -1, "\n->PROTECT\n\n");
  159. #    endif
  160.  
  161.     varset = 0;
  162.  
  163.     /*
  164.     **  Scan the range table and create a set of all variables
  165.     **  which are 'interesting', that is, on which the protectin
  166.     **  algorithm should be performed.
  167.     */
  168.  
  169.     for (vn = 0; vn < MAXVAR + 1; vn++)
  170.     {
  171.         if (!Qt.qt_rangev[vn].rngvmark)
  172.             continue;
  173.         d = Qt.qt_rangev[vn].rngvdesc;
  174.         if (d == NULL)
  175.             syserr("null desc vn=%d", vn);
  176.  
  177.         /* if owner, accept any query */
  178.         if (bequal(d->reldum.relowner, Usercode, UCODE_SZ))
  179.             continue;
  180.  
  181.         /* check for "no restriction" bit asserted (= clear) */
  182.         if (!bitset(S_PROTALL, d->reldum.relstat))
  183.             continue;
  184.         if (!bitset(S_PROTRET, d->reldum.relstat) &&
  185.             (Qt.qt_qmode == mdRETR || Qt.qt_qmode == mdRET_UNI))
  186.             continue;
  187.  
  188.         varset |= 1 << vn;
  189.     }
  190.  
  191.     /*
  192.     **  For each variable specified in varset (that is, for each
  193.     **  variable in the initial query), do the real algorithm.
  194.     */
  195.  
  196.     for (vn = 0; vn < MAXVAR + 1; vn++)
  197.     {
  198.         if ((varset & (1 << vn)) == 0)
  199.             continue;
  200.         d = Qt.qt_rangev[vn].rngvdesc;
  201.  
  202. #        ifdef xQTR1
  203.         if (tTf(50, 1))
  204.             printf("\nvn=%d: %.12s\n", vn, d->reldum.relid);
  205. #        endif
  206.  
  207.         /*
  208.         **  Determine the query mode for this variable.  This
  209.         **  is not the query mode of the original query,
  210.         **  unless the variable is the result variable.
  211.         */
  212.  
  213.         qmode = Qt.qt_qmode;
  214.         if (vn != Qt.qt_resvar || qmode == mdRET_UNI)
  215.             qmode = mdRETTERM;
  216.  
  217. #        ifdef xQTR3
  218.         if (qmode == 1 || qmode > 4 || qmode < 0)
  219.             syserr("protect: bad qmode %d", qmode);
  220. #        endif
  221.  
  222.         /* do the interesting part of the algorithm */
  223.         dopro(vn, r, qmode, NULL);
  224.     }
  225.  
  226.     /* return the (authorized) tree */
  227. #    ifdef xQTR1
  228.     if (tTf(50, 15))
  229.         treepr(r, "PROTECT->");
  230. #    endif
  231.     return (r);
  232. }
  233. /*
  234. **  DOPRO -- actually do the protection algorithm
  235. **
  236. **    This is the guts of it, broken off because it must be called
  237. **    recursively on aggregates.  The algorithm is as discussed
  238. **    in the module header.
  239. **
  240. **    Parameters:
  241. **        varno -- the variable number of interest.
  242. **        root -- the root of the tree to modify.
  243. **        qmode -- the effective query mode for this relation.
  244. **        byset -- if non-NULL, a set of domains passed back
  245. **            which gets bound out of the aggregate func,
  246. **            in other words, the by list.
  247. **
  248. **    Returns:
  249. **        none
  250. **
  251. **    Side Effects:
  252. **        The tree pointed at by 'root' gets modified.
  253. **        Quite possibly 'Qt.qt_rangev' and 'Qt.qt_remap' get clobbered.
  254. **
  255. **    Called By:
  256. **        protect
  257. **        makedset -- on aggregates and aggregate functions.
  258. **
  259. **    Trace Flags:
  260. **        51
  261. */
  262.  
  263. dopro(varno, root, qmode, byset)
  264. int    varno;
  265. QTREE    *root;
  266. int    qmode;
  267. int    byset[8];
  268. {
  269.     int        qset[8];
  270.     int        uset[8];
  271.     int        aset[8];
  272.     int        rset[8];
  273.     int        zeros[8];
  274.     QTREE        *p;
  275.     QTREE        *pqual;
  276.     register int    i;
  277.     register int    vn;
  278.     register QTREE    *t;
  279.     int        noperm;
  280.     int        noqual;
  281.     struct protect    prokey, protup;
  282.     struct tup_id    lotid, hitid;
  283.     struct qvect
  284.     {
  285.         QTREE    *q_qual;
  286.         int    q_mode;
  287.     };
  288.     struct qvect    quals[4];
  289.     int        j;
  290.     extern QTREE    *norml();
  291.     extern QTREE    *tree();
  292.     extern QTREE    *trimqlend();
  293.  
  294.  
  295.     t = root;
  296.     vn = varno;
  297.  
  298.     /* create domain usage sets */
  299.     for (i = 0; i < 8; i++)
  300.     {
  301.         zeros[i] = uset[i] = rset[i] = qset[i] = aset[i] = 0;
  302.         if (byset != NULL)
  303.             byset[i] = 0;
  304.     }
  305.  
  306.     /*
  307.     **  Create domain usage set for target list side.  There are
  308.     **  two general cases: this is the root of the tree, or this
  309.     **  is the head of an aggregate.
  310.     */
  311.  
  312.     switch (t->sym.type)
  313.     {
  314.       case AGHEAD:
  315.         /*
  316.         **  An aggregate head falls into two classes: simple
  317.         **  aggregate and aggregate function.  In an aggregate
  318.         **  function, care must be taken to bind the variables
  319.         **  in the by-list outside of the aggregate.  We use
  320.         **  'rset' as a temporary here.
  321.         */
  322.  
  323.         if (t->left->sym.type == BYHEAD)
  324.         {
  325.             /* make by-list set */
  326.             makedset(vn, t->left->left, NULL, rset, aset, qset);
  327.  
  328.             /* merge by-list set into qualification set */
  329.             for (i = 0; i < 8; i++)
  330.             {
  331.                 if (byset != NULL)
  332.                     byset[i] |= rset[i];
  333.                 qset[i] |= rset[i];
  334.                 rset[i] = 0;
  335.             }
  336.  
  337.             /* make aggregate list set */
  338.             makedset(vn, t->left->right->right, NULL, rset, aset, qset);
  339.         }
  340.         else
  341.         {
  342.             /* simple aggregate */
  343. #            ifdef xQTR3
  344.             if (t->left->sym.type != AOP)
  345.                 syserr("dopro: AGHEAD->left %d", t->left->sym.type);
  346. #            endif
  347.             
  348.             /* check for qualification */
  349.             if (t->right->sym.type == QLEND)
  350.             {
  351.                 /* simple, unqualified aggregate */
  352.                 makedset(vn, t->left->right, NULL, aset, aset, qset);
  353.             }
  354.             else
  355.             {
  356. #                ifdef xQTR3
  357.                 if (t->right->sym.type != AND)
  358.                     syserr("dopro: AND=%d", t->right->sym.type);
  359. #                endif
  360.                 makedset(vn, t->left->right, NULL, rset, aset, qset);
  361.             }
  362.         }
  363.         break;
  364.     
  365.       case ROOT:
  366.         makedset(vn, t->left, uset, rset, aset, qset);
  367.         break;
  368.     }
  369.  
  370.     /* scan qualification */
  371.     makedset(vn, t->right, NULL, qset, aset, qset);
  372.  
  373.     /* if retrieval, drop the 'update' set */
  374.     /* if delete or append, force an apparent update */
  375.     switch (qmode)
  376.     {
  377.       case mdRETTERM:
  378.         for (i = 0; i < 8; i++)
  379.             uset[i] = 0;
  380.         break;
  381.  
  382.       case mdDEL:
  383.       case mdAPP:
  384.         for (i = 0; i < 8; i++)
  385.             uset[i] = -1;
  386.         break;
  387.     }
  388.  
  389. #    ifdef xQTR1
  390.     if (tTf(51, 2))
  391.     {
  392.         printf("qmode %d\n", qmode);
  393.         pr_set(uset, "uset");
  394.         pr_set(rset, "rset");
  395.         pr_set(aset, "aset");
  396.         pr_set(qset, "qset");
  397.     }
  398. #    endif
  399.  
  400.     /* create a bit map of all referenced operations */
  401.     noperm = 0;
  402.     if (!bequal(uset, zeros, sizeof zeros))
  403.         noperm |= Proopmap[qmode];
  404.     if (!bequal(rset, zeros, sizeof zeros))
  405.         noperm |= PRO_RETR;
  406.     if (!bequal(aset, zeros, sizeof zeros))
  407.         noperm |= PRO_AGGR;
  408.     if (!bequal(qset, zeros, sizeof zeros))
  409.         noperm |= PRO_TEST;
  410.  
  411.     /* if no operation, something is wrong */
  412.     /* not nessasarily, consider a var that only occurs in an aggregate */
  413. /*    if (noperm == 0)
  414.         syserr("protect: no oper");    */
  415.     
  416.     /* initialize qualification portion */
  417.     for (i = 0; i < 4; )
  418.         quals[i++].q_qual = NULL;
  419.     noqual = FALSE;
  420.  
  421.     /* check the protection catalog */
  422.     opencatalog("protect", OR_READ);
  423.     setkey(&Prodes, &prokey, Qt.qt_rangev[vn].rngvdesc->reldum.relid, PRORELID);
  424.     setkey(&Prodes, &prokey, Qt.qt_rangev[vn].rngvdesc->reldum.relowner, PRORELOWN);
  425.     find(&Prodes, EXACTKEY, &lotid, &hitid, &prokey);
  426.  
  427.     while ((i = get(&Prodes, &lotid, &hitid, &protup, TRUE)) == 0)
  428.     {
  429.         if (kcompare(&Prodes, &prokey, &protup) != 0)
  430.             continue;
  431.  
  432. #        ifdef xQTR2
  433.         if (tTf(51, 4))
  434.         {
  435.             printf("PROTECT: ");
  436.             printup(&Prodes, &protup);
  437.         }
  438. #        endif
  439.  
  440.         /* check if this is the correct user, terminal, etc */
  441.         if (!proappl(&protup))
  442.             continue;
  443.         
  444.         /* alright, let's check the operation */
  445.         i = 0;
  446.         if (qmode != mdRETTERM)
  447.             i = quals[0].q_mode = prochk(Proopmap[qmode], uset, &protup);
  448.         i |= quals[1].q_mode = prochk(PRO_RETR, rset, &protup);
  449.         i |= quals[2].q_mode = prochk(PRO_AGGR, aset, &protup);
  450.         i |= quals[3].q_mode = prochk(PRO_TEST, qset, &protup);
  451.  
  452. #        ifdef xQTR2
  453.         if (tTf(51, 5))
  454.             printf("Satisfies operations %o\n", i);
  455. #        endif
  456.  
  457.         /* see if this tuple is "interesting" */
  458.         if (i == 0)
  459.             continue;
  460.         
  461.         /* it is!  get the qualification (if any) */
  462.         if (protup.protree >= 0)
  463.         {
  464.             p = gettree(Qt.qt_rangev[vn].rngvdesc->reldum.relid,
  465.                     Qt.qt_rangev[vn].rngvdesc->reldum.relowner,
  466.                     mdPROT, protup.protree, FALSE);
  467. #            ifdef xQTR2
  468.             if (tTf(51, 6))
  469.                 treepr(p, "Protection Clause");
  470. #            endif
  471.             p = trimqlend(p->right);
  472. #            ifdef xQTR3
  473.             /* check for a non-null qualification */
  474.             if (p == NULL)
  475.                 syserr("protect: null tree");
  476. #            endif
  477.  
  478.             /* translate to the interesting variable */
  479.             j = protup.proresvar;
  480.             if (Qt.qt_remap[j] >= 0)
  481.                 j = Qt.qt_remap[j];
  482.             mergevar(j, varno, p);
  483.  
  484.             /* disjoin the protection qual to real qual */
  485.             for (j = 0; j < 4; j++)
  486.             {
  487.                 if (quals[j].q_mode == 0)
  488.                     continue;
  489.                 if (quals[j].q_qual == NULL)
  490.                     quals[j].q_qual = p;
  491.                 else
  492.                     quals[j].q_qual = tree(quals[j].q_qual, p, OR, 0);
  493.             }
  494.         }
  495.         else
  496.             noqual = TRUE;
  497.  
  498.         /* mark this operation as having been handled */
  499.         noperm &= ~i;
  500.     }
  501.  
  502.     /* test 'get' return code */
  503.     if (i < 0)
  504.         syserr("protect: get");
  505.  
  506. #    ifdef xQTR1
  507.     if (tTf(51, 12))
  508.         printf("No perm on %o\n", noperm);
  509. #    endif
  510.  
  511.     /* see if no tuples applied for some operation */
  512.     if (noperm != 0)
  513.         qmerror(PVIOL, Qt.qt_qmode, vn, 0);
  514.     
  515.     /* see if we want to modify the query at all */
  516.     if (!noqual)
  517.     {
  518.         /* conjoin the qualification */
  519.         pqual = NULL;
  520.         for (i = 0; i < 4; i++)
  521.             if (quals[i].q_qual != NULL)
  522.                 if (pqual == NULL)
  523.                     pqual = quals[i].q_qual;
  524.                 else
  525.                     pqual = tree(pqual, quals[i].q_qual, AND, 0);
  526.         pqual = tree(pqual, tree(NULL, NULL, QLEND, 0), AND, 0);
  527.         appqual(pqual, t);
  528.  
  529.         /* normalize the tree */
  530.         t->right = norml(trimqlend(t->right));
  531.     }
  532. }
  533. /*
  534. **  MAKEDSET -- make domain reference sets
  535. **
  536. **    This routine creates some sets which reflect the usage of
  537. **    domains for a particular variable.
  538. **
  539. **    The interesting nodes are 'case' labels in the large
  540. **    switch statement which comprises most of the code.  To
  541. **    describe briefly:
  542. **
  543. **    VAR nodes are easy: if they are for the current variable,
  544. **        set the bit corresponding to the domain in the
  545. **        'retrieval' set.  They can have no descendents,
  546. **        so just return.
  547. **    RESDOM nodes are also easy: they can be handled the same,
  548. **        but the bit is set in the 'update' set instead.
  549. **    AGHEAD nodes signal the beginning of an aggregate or
  550. **        aggregate function.  In this case, we scan the
  551. **        qualification first (noting that RESDOM and VAR
  552. **        nodes are processed as 'qualification' sets
  553. **        instead of 'retrieval' or 'update' sets).  Then,
  554. **        if the aggregate has a WHERE clause or a BY list,
  555. **        we treat it as a retrieve; otherwise, we call our-
  556. **        selves recursively treating VAR nodes as 'aggregate'
  557. **        types rather than 'retrieve' types.
  558. **    BYHEAD nodes signal the beginning of a BY list.  The left
  559. **        subtree (the actual BY-list) is processed with
  560. **        RESDOM nodes ignored (since they are pseudo-domains
  561. **        anyhow) and VAR nodes mapped into the 'qualification'
  562. **        set.  Then we check the right subtree (which better
  563. **        begin with an AOP node!) and continue processing.
  564. **    AOP nodes must have a null left subtree, so we just drop
  565. **        to the right subtree and iterate.  Notice that we
  566. **        do NOT map VAR nodes into the 'aggregate' set for
  567. **        this node, since this has already been done by the
  568. **        AGHEAD node; also, this aggregate might be counted
  569. **        as a retrieve operation instead of an aggregate
  570. **        operation (as far as the protection system is con-
  571. **        cerned) -- this has been handled by the AGHEAD
  572. **        node.
  573. **    All other nodes are processed recursively along both edges.
  574. **
  575. **    Parameters:
  576. **        vn -- the variable number that we are currently
  577. **            interested in.
  578. **        tree -- the root of the tree to scan.  Notice that this
  579. **            will in general be only one half of the tree --
  580. **            makedset will be called once for the target
  581. **            list and once for the qualification, with
  582. **            different sets for the following parameters.
  583. **        uset -- adjusted to be the set of all domains
  584. **            updated.
  585. **        rset -- adjusted to be the set of all domains
  586. **            retrieved implicitly, that is, on the right-
  587. **            hand-side of an assignment operator.
  588. **        aset -- adjusted to be the set of all domains
  589. **            aggregated.  Notice that this set is not
  590. **            adjusted explicitly, but rather is passed
  591. **            to recursive incarnations of this routine
  592. **            as 'rset'.
  593. **        qset -- adjusted to be the set of domains retrieved
  594. **            implicitly in a qualification.  Like 'aset',
  595. **            this is passed as 'rset' to recursive
  596. **            incarnations.
  597. **
  598. **    Returns:
  599. **        none
  600. **
  601. **    Side Effects:
  602. **        none
  603. **
  604. **    Called By:
  605. **        protect() -- in two places.
  606. **
  607. **    Trace Flags:
  608. **        53
  609. **
  610. */
  611.  
  612. makedset(vn, tree, uset, rset, aset, qset)
  613. int    vn;
  614. QTREE    *tree;
  615. int    uset[8];
  616. int    rset[8];
  617. int    aset[8];
  618. int    qset[8];
  619. {
  620.     register QTREE    *t;
  621.     register int    i;
  622.     int        byset[8];
  623.  
  624.     t = tree;
  625.  
  626. #    ifdef xQTR1
  627.     if (tTf(53, 0))
  628.     {
  629.         printf("->makedset\n");
  630.         pr_set(uset, "uset");
  631.         pr_set(rset, "rset");
  632.         pr_set(aset, "aset");
  633.         pr_set(qset, "qset");
  634.     }
  635. #    endif
  636.  
  637.     while (t != NULL)
  638.     {
  639.         switch (t->sym.type)
  640.         {
  641.           case VAR:
  642.             if (t->sym.value.sym_var.varno == vn)
  643.                 lsetbit(t->sym.value.sym_var.attno, rset);
  644.             break;
  645.  
  646.           case AGHEAD:
  647.             /* do protection on qualification */
  648.             dopro(vn, t, -1, byset);
  649.  
  650.             /* merge by-list set into qualification set */
  651.             for (i = 0; i < 8; i++)
  652.                 qset[i] |= byset[i];
  653.  
  654.             break;
  655.  
  656.           case BYHEAD:
  657.           case AOP:
  658.             syserr("makedset: node %d", t->sym.type);
  659.  
  660.           case RESDOM:
  661.             if (t->sym.value.sym_resdom.resno == 0)
  662.             {
  663.                 /* tid -- ignore right subtree (and this node) */
  664.                 t = t->left;
  665.                 continue;
  666.             }
  667.             if (uset != NULL)
  668.                 lsetbit(t->sym.value.sym_resdom.resno, uset);
  669.             /* explicit fall-through to "default" case */
  670.  
  671.           default:
  672.             /* handle left subtree (recursively) */
  673.             makedset(vn, t->left, uset, rset, aset, qset);
  674.  
  675.             /* handle right subtree (iteratively) */
  676.             t = t->right;
  677.             continue;
  678.         }
  679.         break;
  680.     }
  681.  
  682. #    ifdef xQTR1
  683.     if (tTf(53, 15))
  684.     {
  685.         printf("makedset->\n");
  686.         pr_set(uset, "uset");
  687.         pr_set(rset, "rset");
  688.         pr_set(aset, "aset");
  689.         pr_set(qset, "qset");
  690.     }
  691. #    endif
  692.  
  693.     return;
  694. }
  695. /*
  696. **  PROAPPL -- check for protection tuple applicable
  697. **
  698. **    A given protection catalog tuple is checked in a query-
  699. **    independent way for applicability.
  700. **
  701. **    This routine checks such environmental constraints as the
  702. **    user, the terminal, and the time of day.  The code is
  703. **    fairly straightforward, just take a look.
  704. **
  705. **    One note: the user and terminal codes contained in the
  706. **    protection catalog are blank to mean 'any value' of the
  707. **    corresponding field.
  708. **
  709. **    Parameters:
  710. **        protup -- the protection tuple to compare against.
  711. **
  712. **    Returns:
  713. **        TRUE -- this tuple applies to the current environment.
  714. **        FALSE -- this tuple does not apply.
  715. **
  716. **    Side Effects:
  717. **        none (unless you include trashing the static vector
  718. **            returned by localtime).
  719. **
  720. **    Called By:
  721. **        protect()
  722. **
  723. **    Trace Flags:
  724. **        54
  725. */
  726.  
  727. proappl(protup)
  728. struct protect    *protup;
  729. {
  730.     register struct protect    *p;
  731.     int            tvect[2];
  732.     register int        *tt;
  733.     extern int        *localtime();
  734.     register int        mtime;
  735.  
  736.     p = protup;
  737.  
  738.     /* check for correct user [insert clique code here] */
  739.     if (!bequal("  ", p->prouser, 2))
  740.     {
  741.         if (!bequal(p->prouser, Usercode, UCODE_SZ))
  742.         {
  743. # ifdef xQTR2
  744.             if (tTf(54, 0))
  745.                 printf("  ~user\n");
  746. # endif
  747.             return (FALSE);
  748.         }
  749.     }
  750.  
  751.     /* check for correct terminal */
  752.     if (p->proterm[0] != ' ')
  753.     {
  754.         if (!sequal(p->proterm, Terminal))
  755.         {
  756. # ifdef xQTR2
  757.             if (tTf(54, 0))
  758.                 printf("  ~term\n");
  759. # endif
  760.             return (FALSE);
  761.         }
  762.     }
  763.  
  764.     /* check for correct time of day & week */
  765.     time(tvect);
  766.     tt = localtime(tvect);
  767.     mtime = tt[2] * 60 + tt[1];
  768.  
  769.     if (p->protodbgn > mtime || p->protodend < mtime)
  770.     {
  771. # ifdef xQTR2
  772.         if (tTf(54, 0))
  773.             printf("  ~tod\n");
  774. # endif
  775.         return (FALSE);
  776.     }
  777.     if (p->prodowbgn > tt[6] || p->prodowend < tt[6])
  778.     {
  779. # ifdef xQTR2
  780.         if (tTf(54, 0))
  781.             printf("  ~dow\n");
  782. # endif
  783.         return (FALSE);
  784.     }
  785.  
  786.     /* hasn't failed yet -- I guess it's ok */
  787.     return (TRUE);
  788. }
  789. /*
  790. **  PROCHK -- query-dependent protection tuple check
  791. **
  792. **    This routine does the query-dependent part of checking
  793. **    the validity of a protection tuple.  Unlike proappl,
  794. **    which looked at aspects of the environment but not the
  795. **    query being run, this routine assumes that the environ-
  796. **    ment is ok, and checks that if it applies to this tuple.
  797. **
  798. **    Two things are checked.  The first is if this tuple applies
  799. **    to the operation in question (passed as 'inbit').  The
  800. **    second is if the set of domains in the tuple contains the
  801. **    set of domains in the query.  If either of these fail,
  802. **    the return is zero.  Otherwise the return is the operation
  803. **    bit.  In otherwise, the return is the operation to which
  804. **    this tuple applies (if any).
  805. **
  806. **    As a special check, the domain set is checked for all
  807. **    zero.  If so, no domains have been referenced for this
  808. **    operation at all, and we return zero.  In other words, this
  809. **    tuple might apply to this operation, but since we don't
  810. **    use the operation anyhow we will ignore it.  It is important
  811. **    to handle things in this way so that the qualification for
  812. **    this tuple doesn't get appended if the variable is not
  813. **    used in a particular context.
  814. **
  815. **    Parameters:
  816. **        inbit -- the bit describing the operation to be
  817. **            checked.  Note that only one bit should
  818. **            be set in this word, although this is
  819. **            not checked.
  820. **        domset -- the set of domains actually referenced
  821. **            in this query for the operation described
  822. **            by 'inbit'.
  823. **        protup -- the tuple in question.
  824. **
  825. **    Returns:
  826. **        The operation (if any) to which this tuple applies.
  827. **
  828. **    Side Effects:
  829. **        none
  830. **
  831. **    Called By:
  832. **        protect() -- in four places.
  833. **
  834. **    Trace Flags:
  835. **        55
  836. */
  837.  
  838. prochk(inbit, domset, protup)
  839. int        inbit;
  840. int        domset[8];
  841. struct protect    *protup;
  842. {
  843.     register struct protect    *p;
  844.     register int        *d;
  845.     register int        i;
  846.  
  847.     p = protup;
  848.     d = domset;
  849.  
  850. #    ifdef xQTR1
  851.     if (tTf(55, 0))
  852.     {
  853.         printf("->prochk, inbit=%o, proopset=%o\n", inbit, p->proopset);
  854.         pr_set(d, "domset");
  855.         pr_set(p->prodomset, "prodomset");
  856.     }
  857. #    endif
  858.  
  859.     /* check for null domain set, if so return zero */
  860.     for (i = 0; i < 8; i++)
  861.         if (d[i] != 0)
  862.             break;
  863.     if (i >= 8)
  864.     {
  865. #        ifdef xQTR2
  866.         tTfp(55, 15, "prochk-> null set\n");
  867. #        endif
  868.         return (0);
  869.     }
  870.  
  871.     /* see if this tuple applies to this operation */
  872.     if ((inbit & p->proopset) == 0)
  873.     {
  874. #        ifdef xQTR2
  875.         tTfp(55, 15, "prochk-> no op\n");
  876. #        endif
  877.         return (0);
  878.     }
  879.  
  880.     /* check if domains are a subset */
  881.     for (i = 0; i < 8; i++)
  882.     {
  883.         if ((d[i] & ~p->prodomset[i]) != 0)
  884.         {
  885.             /* failure */
  886. #            ifdef xQTR2
  887.             tTfp(55, 15, "prochk-> not subset\n");
  888. #            endif
  889.             return (0);
  890.         }
  891.     }
  892.  
  893.     /* this is hereby an "interesting" tuple */
  894. #    ifdef xQTR2
  895.     if (tTf(55, 15))
  896.         printf("prochk-> %d\n", inbit);
  897. #    endif
  898.     return (inbit);
  899. }
  900.  
  901. # ifdef xQTR1
  902.  
  903. /*
  904. **  PR_SET -- print set for debugging
  905. **
  906. **    This routine prints a 128-bit set for debugging.
  907. **
  908. **    Parameters:
  909. **        xset -- the set to convert.
  910. **        labl -- a label to print before the set.
  911. **
  912. **    Returns:
  913. **        a pointer to the converted string.
  914. **
  915. **    Side Effects:
  916. **        none
  917. */
  918.  
  919. pr_set(xset, labl)
  920. short    xset[8];
  921. char    *labl;
  922. {
  923.     register short    *x;
  924.     register int    i;
  925.     register long    *y;
  926.  
  927.     printf("\t%s: ", labl);
  928.     x = xset;
  929.     y = (long *) x;
  930.     if (x == NULL)
  931.     {
  932.         printf("<NULL>\n");
  933.         return;
  934.     }
  935.     for (i = 7; i >= 0; i--)
  936.         printf("%x/", x[i]);
  937.     printf(" <> ");
  938.     for (i = 0; i < 4; i++)
  939.         printf("/%ld", y[i]);
  940.     printf("\n");
  941. }
  942.  
  943. # endif
  944.